package com.ccp.dev.workflow.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.system.dao.SysTypeKeyDao;
import com.ccp.dev.system.dao.SysUserDao;
import com.ccp.dev.system.model.GlobalType;
import com.ccp.dev.system.model.SysTypeKey;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.workflow.dao.BpmProTransToDao;
import com.ccp.dev.workflow.dao.TaskDao;
import com.ccp.dev.workflow.dao.TaskOpinionDao;
import com.ccp.dev.workflow.model.*;
import com.ccp.dev.workflow.model.bpm.ProcessTask;
import org.flowable.engine.TaskService;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * ClassDescribe 流程流转状态 Service类
 * @author:
 * Date: 2019-07-25
 */

@Service
public class BpmProTransToService extends BaseService<BpmProTransTo> {

    @Resource
    private BpmProTransToDao bpmProTransToDao;
    @Resource
    private TaskDao taskDao;
    @Resource
    private TaskService taskService;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private ProcessRunService processRunService;
    @Resource
    private CommuReceiverService commuReceiverService;
    @Resource
    private TaskOpinionDao taskOpinionDao;
    @Resource
    private BpmService bpmService;
    @Resource
    private SysTypeKeyDao sysTypeKeyDao;


    public void delByTaskId(String taskId){
        bpmProTransToDao.delByTaskId(taskId);
    }

    /**
     * 级联删除流转任务
     * @param taskId
     */
    @Transactional(rollbackFor = Exception.class)
    public void cancelTransToTaskCascade(String taskId){
        List list = taskDao.getByParentTaskId(taskId);
        for(int i=0;i<list.size();i++){
            //级联删除流转任务
            ProcessTask task = (ProcessTask)list.get(i);
            taskService.deleteTask(task.getId());
            //删除被流转任务产生的沟通任务
            taskDao.delCommuTaskByParentTaskId(task.getId());
            if(task.getDescription().equals(TaskOpinion.STATUS_TRANSTO_ING.toString())){
                //删除流转状态
                delByTaskId(task.getId());
                this.cancelTransToTaskCascade(task.getId());
            }
        }
    }

    public void delByProcInstId(String procInstId) {
        bpmProTransToDao.delByProcInstId(procInstId);
    }

    /**
     * 根据任务id获取流转记录
     * @param taskId
     * @return
     */
    public BpmProTransTo getByTaskId(String taskId) {
        List<BpmProTransTo> list = bpmProTransToDao.getByTaskId(taskId);
        if(list.isEmpty()){
            return null;
        }
        return list.get(0);
    }

    /**
     * 获取所有流转人的任务状态
     * @param parentTaskId
     * @param assignee
     * @return
     * @throws Exception
     */
    public List<BpmProTransToAssignee> getAssignee(String parentTaskId, String assignee) throws Exception {
        List<ProcessTask> taskList = taskDao.getByParentTaskId(parentTaskId);
        List<BpmProTransToAssignee> list = handleAssignee(taskList, assignee);
        return list;
    }

    /**
     * 获取流转人
     * @param taskList
     * @param assignee
     * @return
     */
    private List<BpmProTransToAssignee> handleAssignee(List<ProcessTask> taskList, String assignee) {
        Map<String, String> taskMap = new HashMap<String, String>();
        if(taskList!=null){
            for(int i=0;i<taskList.size();i++){
                ProcessTask task = taskList.get(i);
                taskMap.put(task.getAssignee(), task.getParentTaskId());
            }
        }
        String[] assignees = assignee.split(",");
        List<BpmProTransToAssignee> list = new ArrayList<BpmProTransToAssignee>();
        for(String transTo : assignees){
            SysUser sysUser = sysUserDao.getById(transTo);
            BpmProTransToAssignee transToAssignee = new BpmProTransToAssignee();
            transToAssignee.setUserId(sysUser.getUserId());
            transToAssignee.setUserName(sysUser.getFullName());
            if(taskMap.containsKey(transTo)){
                transToAssignee.setStatus(BpmProTransToAssignee.STATUS_CHECKING);
                transToAssignee.setParentTaskId(taskMap.get(transTo));
            }else{
                transToAssignee.setStatus(BpmProTransToAssignee.STATUS_CHECKED);
            }
            list.add(transToAssignee);
        }
        return list;
    }

    /**
     * 取消流转任务
     * @param processTask
     * @param opinion
     * @param informType
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public void cancel(ProcessTask processTask, String opinion, String informType) throws Exception {
        SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
        String taskId = processTask.getId();
        String parentTaskId = processTask.getParentTaskId();
        taskService.deleteTask(taskId);

        if(processTask.getDescription().equals(TaskOpinion.STATUS_TRANSTO_ING.toString())){
            //删除流转状态
            delByTaskId(taskId);
            this.cancelTransToTaskCascade(taskId);
        }

        //删除被流转任务产生的沟通任务
        taskDao.delCommuTaskByParentTaskId(taskId);
        List<ProcessTask> list = taskDao.getByParentTaskId(parentTaskId);
        BpmProTransTo bpmProTransTo = this.getByTaskId(parentTaskId);
        if(list.isEmpty()){
            //所有流转任务已结束
            ProcessTask parentTask = taskDao.getByTaskId(parentTaskId);
            if(parentTask.getParentTaskId()==null){
                //更改初始执行人状态为审批状态
                taskDao.updateTaskDescription(TaskOpinion.STATUS_CHECKING.toString(), parentTaskId);
            }else{
                //更改初始执行人状态为流转状态
                taskDao.updateTaskDescription(TaskOpinion.STATUS_CHECKING.toString(), parentTaskId);
            }
            //删除流转状态
            this.delById(bpmProTransTo.getId());
        }else{
            //删除被取消的流转人记录
            String assignee = bpmProTransTo.getAssignee();
            if(assignee.startsWith(processTask.getAssignee())){
                assignee = assignee.replace(processTask.getAssignee()+",", "");
            }else{
                assignee = assignee.replace(","+processTask.getAssignee(), "");
            }
            bpmProTransTo.setAssignee(assignee);
            this.update(bpmProTransTo);
        }

        //修改任务接收人状态
        commuReceiverService.setCommuReceiverStatus(taskId, CommuReceiver.CANCEL, processTask.getAssignee());
        //添加审批意见
        this.addOpinion(processTask, opinion, sysUser, false);
        // 发送通知。
        ProcessRun processRun=processRunService.getByProcInstanceId(processTask.getProcessInstanceId());
        Map<String, String> usrIdTaskIds = new HashMap<String, String>();
        usrIdTaskIds.put(processTask.getAssignee(), null);
        processRunService.notifyCommu(processRun.getSubject(), usrIdTaskIds, informType,
                sysUser, opinion, SysTemplate.USE_TYPE_CANCLE_TRANSTO);
    }

    /**
     * 添加审批意见
     * @param processTask
     * @param opinion
     * @param sysUser
     * @param isAdd
     * @return
     */
    private String addOpinion(ProcessTask processTask, String opinion, SysUser sysUser, boolean isAdd){
        String opinionId = UUIDUtils.getUUIDFor32();
        TaskOpinion taskOpinion = new TaskOpinion();
        taskOpinion.setOpinionId(opinionId);
        taskOpinion.setProcDefId(processTask.getProcessDefinitionId());
        taskOpinion.setProcInstId(processTask.getProcessInstanceId());
        if(isAdd){
            taskOpinion.setCheckStatus(TaskOpinion.STATUS_ADD_TRANSTO);
            taskOpinion.setStartTime(new Date());
            taskOpinion.setEndTime(new Date());
            taskOpinion.setOpinion(opinion);
        }else{
            taskOpinion.setCheckStatus(TaskOpinion.STATUS_CANCLE_TRANSTO);
            SysUser assignee = sysUserDao.getById(processTask.getAssignee());
            String cancelOpinion = "取消【" + assignee.getFullName() + "】的流转任务。原因：" + opinion;
            taskOpinion.setOpinion(cancelOpinion);
            taskOpinion.setStartTime(processTask.getCreateTime());
            taskOpinion.setEndTime(new Date());
            //持续时间
            Long durationTime =taskOpinion.getEndTime().getTime()-taskOpinion.getStartTime().getTime();
            taskOpinion.setDurTime(durationTime);
        }
        taskOpinion.setExeUserId(sysUser.getUserId());
        taskOpinion.setExeFullname(sysUser.getFullName());
        taskOpinion.setTaskKey(processTask.getTaskDefinitionKey());
        taskOpinion.setTaskName(processTask.getName());
        // 增加流程意见
        taskOpinionDao.add(taskOpinion);
        return opinionId;
    }


    /**
     * 添加流转任务
     * @param bpmProTransTo
     * @param taskId
     * @param opinion
     * @param userIds
     * @param informType
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public void addTransTo(BpmProTransTo bpmProTransTo, String taskId, String opinion,
                           String userIds, String informType) throws Exception {
        SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();

        TaskEntity taskEntity = bpmService.getTask(taskId);
        ProcessTask processTask = taskDao.getByTaskId(taskId);
        String[] aryUsers = userIds.split(",");
        //获取已经流转的人
        List<BpmProTransToAssignee> list =getAssignee(taskId, bpmProTransTo.getAssignee());
        List<String> userId = new ArrayList<String>();
        for(BpmProTransToAssignee bpmProTransToAssignee:list){
            String uId =String.valueOf(bpmProTransToAssignee.getUserId());
            userId.add(uId);
        }
        List<String> userList = new ArrayList<String>();
        for(String user :aryUsers){
            if(!userId.contains(user)){
                userList.add(user);
            }
        }
        final int size = userList.size();
        String[] aryUser = (String[])userList.toArray(new String[size]);
        String uIds = "";
        for(String i:aryUser){
            uIds +=i+",";
        }
        if(uIds.length()>0){
            uIds = uIds.substring(0,uIds.length()-1);
        }
        // 产生流转任务
        Map<String, String>  usrIdTaskIds = bpmService.genTransToTask(taskEntity, aryUser);
        //添加意见
        String opinionId = this.addOpinion(processTask, opinion, sysUser, true);
        // 保存接收人
        commuReceiverService.saveReceiver(opinionId, usrIdTaskIds, sysUser);
        //更新流转人记录
        String assignee = bpmProTransTo.getAssignee();
        if(StringUtil.isEmpty(assignee)){
            bpmProTransTo.setAssignee(userIds);
        }
        else{
            bpmProTransTo.setAssignee(assignee + "," + uIds);
        }
        bpmProTransToDao.update(bpmProTransTo);

        // 发送通知。
        ProcessRun processRun=processRunService.getByProcInstanceId(processTask.getProcessInstanceId());
        processRunService.notifyCommu(processRun.getSubject(), usrIdTaskIds, informType, sysUser, opinion, SysTemplate.USE_TYPE_TRANSTO);
    }


    /**
     * 加签流转事宜流程分类
     *
     * @param assignee
     * @return
     */
    public List<GlobalType> getByCatKeyForToMatter(String assignee) {
        List<GlobalType> list = bpmProTransToDao.queryCateGory(assignee);
        SysTypeKey sysTypeKey = sysTypeKeyDao.getSysTypeKeyByKey(GlobalType.CAT_FLOW);
        GlobalType globalType = new GlobalType();
        globalType.setTypeName(sysTypeKey.getTypeName());
        globalType.setParentId("0");
        globalType.setIsParent("true");
        globalType.setTypeId(sysTypeKey.getTypeId());
        globalType.setType(sysTypeKey.getType());
        globalType.setNodePath(sysTypeKey.getTypeId() + ".");
        list.add(0, globalType);
        return  list;
    }

}
